import sys
import os
import pymysql
import paramiko
import hashlib

def fileMD5(file):
    md5 = hashlib.md5()
    with open(file, mode="rb") as fobj:
        for line in fobj:
            md5.update(line)
    return md5.hexdigest()

#获取mysql中的数据
def SQLcurd():

    try:
        dbconn = pymysql.connect(host="192.168.106.133",
                                 user="admin",
                                 database="it",
                                 password="WWW.2.com",
                                 charset = 'utf8mb4'
                                 )
    except Exception as e:
        print("数据库192.168.106.133连接失败！！！")
        print(e)
        sys.exit()

    cr = dbconn.cursor()
    exec_sql = "select ip , user, password, port from servers"
    cr.execute(exec_sql)
    # print(cr.fetchall())

# 关闭数据库
    cr.close()
    dbconn.close()
    return cr.fetchall()

#通过ssh连接执行操作
def SSHexec(ip,user,password,port,command):
    sshclient = paramiko.SSHClient()
    sshclient.set_missing_host_key_policy(paramiko.AutoAddPolicy)

    try:
        sshclient.connect(hostname=ip,username=user,password=password,port=port)
    except Exception as e:
        print(" 服务器[%s]@[%s]ssh连接失败，请检查网络以及用户，密码，端口，IP" %(ip,user))
        print(e)
        sys.exit()

    stdin,stdout,stderr  = sshclient.exec_command(command)
    result = stdout.read().decode(encoding="UTF-8")
    print(result)
    sshclient.close()

#批量执行操作
def Bulk_Execution():
    command = input("请输入您要批量执行的操作：").strip()
    servers  = SQLcurd()
    for ip,user,pwd,port in servers:
        print("服务器【%s】执行【%s0】操作："%(ip,command))
        SSHexec(ip=ip,user=user,password=pwd,port=port,command=command)
        print("-------------" *8)



#上传文件功能
# os.path.basename 从完整的路径中获取文件名
# os.path.dirname 从完整的路径中获取路径
def uploadFile (ip,user,password,src_file,server_dir,port=22):
    #拼接服务器上的完整文件名
    if server_dir.endswith("/"):
        server_full_file_name = server_dir + os.path.basename(src_file)
    else:
        server_full_file_name = server_dir + '/' + os.path.basename(src_file)

    try:
        ssh_conn = paramiko.Transport((ip,port))
    except Exception as e:
        print("服务器【%s】ssh连接失败，请检查ip、端口是否正确！！！" % ip)
        sys.exit()
    try:
        ssh_conn.set_missing_host_key_policy(paramiko.AutoAddPolicy)
        ssh_conn.connect(username=user,password=password)
    except Exception as e:
        print("服务器【%s】ssh连接失败，请检查用户、密码是否正确！！！" % ip)
        sys.exit()

    #创建SFTP客户端连接
    sftp = paramiko.SFTPClient.from_transport(ssh_conn)
    sftp.put(src_file,server_full_file_name)


    sftp.close()
    ssh_conn.close()
    return server_full_file_name

#连接任意服务器，获取任意文件的校验码
def ssh_md5_echo_check(ip,user,password,file,port=22):
    #创建客户端连接
    ssh_client = paramiko.SSHClient()
    #跳过客户端连接确认密钥阶段
    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy)

    try:
        ssh_client.connect(hostname=ip,username=user,password=password,port=port)
    except Exception as e:
        print("服务器【%s】ssh连接失败"% ip)
        sys.exit()

    #获取发送过去的文件校验码
    md5_command = "md5 %s | '{print $1}'" %file
    stdin,stdout,stderr = ssh_client.exec_command(md5_command)
    md5  =stdout.read().decode(encoding="UTF-8").strip()  # 这里是windows传输linux会有肉眼看不见的空格

    return md5

# 获取一个文件或源文件的校验码
def multi_src_file_md5(file):
    # 判断源是一个还是多个
    src_file_list = []
    if "," not in  file:
        src_file_list.append(file)
    else:
        src_file_list = file.split(",")
        # 结果字典： {}
        md5_dict = {}
        ssh_md5_dict = {}
        for src_file_name in src_file_list:
            src_file_md5  = fileMD5(src_file_name)
            # 以src_file——md5为键 src_file_md5为值 字典的定义
            md5_dict[src_file_name] = src_file_md5

        return md5_dict

#批量上传文件
def mulitUploadFile():
    src_file = input("源文件[多个文件以,逗号分割]: ").strip()
    server_dir = input("服务器目录: ").strip()
    print("-------------" * 8)

    # 将源文件放入列表
    src_file_list = []
    if "," not in src_file:
        src_file_list.append(src_file)
    else:
        src_file_list = src_file.split(",")

    # 上传文件，显示源文件校验码、目的文件校验码
    # {"数字":{源文件，源文件校验，服务器IP， 服务器文件名称，服务器文件校验码} }
    result = {}
    i = 0

    servers = SQLcurd()
    for ip, user, password, port in servers:
        for src_file_name in src_file_list:
            # 获取源文件的校验码
            src_file_md5 = fileMD5(src_file_name)
            # 上传文件
            server_file_name = uploadFile(ip=ip, user=user, password=password, port=port,
                                          src_file=src_file_name, server_dir=server_dir)
            # 获取服务器上的文件的校验码
            server_file_md5 = ssh_md5_echo_check(ip, user, password, server_file_name, port=22)
            i += 1
            result[i] = {"src_file_name": src_file_name, "src_file_md5": src_file_md5, "ip": ip,
                         "server_file": server_file_name, "server_file_md5": server_file_md5}

    print(result)


if __name__ == '__main__':
    mulitUploadFile()